/*
 * @Author: lixu lixu@puchigames.com
 * @Date: 2025-09-18 11:15:00
 * @LastEditors: lixu lixu@puchigames.com
 * @LastEditTime: 2025-09-18 11:15:00
 * @FilePath: /go-helper/ixLog/writer.go
 * @Description: 日志写入器实现，支持文件、网络、控制台等多种输出目标
 */

package ixLog

import (
	"bufio"
	"compress/gzip"
	"fmt"
	"io"
	"net"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"sync"
	"time"
)

// ConsoleWriter 控制台写入器
type ConsoleWriter struct {
	writer io.Writer
	mutex  sync.Mutex
}

// NewConsoleWriter 创建控制台写入器
func NewConsoleWriter(writer io.Writer) *ConsoleWriter {
	if writer == nil {
		writer = os.Stdout
	}
	return &ConsoleWriter{
		writer: writer,
	}
}

// Write 写入数据
func (w *ConsoleWriter) Write(p []byte) (n int, err error) {
	w.mutex.Lock()
	defer w.mutex.Unlock()
	return w.writer.Write(p)
}

// Close 关闭写入器
func (w *ConsoleWriter) Close() error {
	return nil // 控制台写入器不需要关闭
}

// Sync 同步缓冲区
func (w *ConsoleWriter) Sync() error {
	if syncer, ok := w.writer.(interface{ Sync() error }); ok {
		return syncer.Sync()
	}
	return nil
}

// FileWriter 文件写入器
type FileWriter struct {
	config   *OutputConfig
	file     *os.File
	size     int64
	mutex    sync.Mutex
	lastTime time.Time
}

// NewFileWriter 创建文件写入器
func NewFileWriter(config *OutputConfig) (*FileWriter, error) {
	if config.FilePath == "" {
		return nil, fmt.Errorf("文件路径不能为空")
	}

	// 创建目录
	dir := filepath.Dir(config.FilePath)
	if err := os.MkdirAll(dir, 0755); err != nil {
		return nil, fmt.Errorf("创建目录失败: %w", err)
	}

	writer := &FileWriter{
		config:   config,
		lastTime: time.Now(),
	}

	if err := writer.openFile(); err != nil {
		return nil, err
	}

	return writer, nil
}

// Write 写入数据
func (w *FileWriter) Write(p []byte) (n int, err error) {
	w.mutex.Lock()
	defer w.mutex.Unlock()

	// 检查是否需要轮转
	if w.needRotation(len(p)) {
		if err := w.rotate(); err != nil {
			return 0, fmt.Errorf("日志轮转失败: %w", err)
		}
	}

	n, err = w.file.Write(p)
	if err != nil {
		return n, err
	}

	w.size += int64(n)
	return n, nil
}

// Close 关闭写入器
func (w *FileWriter) Close() error {
	w.mutex.Lock()
	defer w.mutex.Unlock()

	if w.file != nil {
		return w.file.Close()
	}
	return nil
}

// Sync 同步缓冲区
func (w *FileWriter) Sync() error {
	w.mutex.Lock()
	defer w.mutex.Unlock()

	if w.file != nil {
		return w.file.Sync()
	}
	return nil
}

// openFile 打开文件
func (w *FileWriter) openFile() error {
	file, err := os.OpenFile(w.config.FilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
	if err != nil {
		return fmt.Errorf("打开文件失败: %w", err)
	}

	w.file = file

	// 获取文件大小
	if stat, err := file.Stat(); err == nil {
		w.size = stat.Size()
	}

	return nil
}

// needRotation 检查是否需要轮转
func (w *FileWriter) needRotation(writeSize int) bool {
	switch w.config.Rotation {
	case SizeRotation:
		return w.size+int64(writeSize) > w.config.MaxSize*1024*1024
	case TimeRotation:
		return w.shouldRotateByTime()
	case BothRotation:
		return (w.size+int64(writeSize) > w.config.MaxSize*1024*1024) || w.shouldRotateByTime()
	default:
		return false
	}
}

// shouldRotateByTime 检查是否应该按时间轮转
func (w *FileWriter) shouldRotateByTime() bool {
	now := time.Now()
	return now.Day() != w.lastTime.Day() || now.Month() != w.lastTime.Month() || now.Year() != w.lastTime.Year()
}

// rotate 执行轮转
func (w *FileWriter) rotate() error {
	// 关闭当前文件
	if w.file != nil {
		w.file.Close()
		w.file = nil
	}

	// 生成轮转文件名
	rotatedPath := w.generateRotatedPath()

	// 重命名当前文件
	if err := os.Rename(w.config.FilePath, rotatedPath); err != nil {
		return fmt.Errorf("重命名文件失败: %w", err)
	}

	// 异步压缩文件
	if w.config.Compress {
		go w.compressFile(rotatedPath)
	}

	// 清理旧文件
	go w.cleanOldFiles()

	// 打开新文件
	w.size = 0
	w.lastTime = time.Now()
	return w.openFile()
}

// generateRotatedPath 生成轮转文件路径
func (w *FileWriter) generateRotatedPath() string {
	dir := filepath.Dir(w.config.FilePath)
	filename := filepath.Base(w.config.FilePath)
	ext := filepath.Ext(filename)
	name := strings.TrimSuffix(filename, ext)

	timestamp := time.Now().Format("20060102_150405")
	return filepath.Join(dir, fmt.Sprintf("%s_%s%s", name, timestamp, ext))
}

// compressFile 压缩文件
func (w *FileWriter) compressFile(filePath string) {
	gzPath := filePath + ".gz"

	input, err := os.Open(filePath)
	if err != nil {
		return
	}
	defer input.Close()

	output, err := os.Create(gzPath)
	if err != nil {
		return
	}
	defer output.Close()

	gzWriter := gzip.NewWriter(output)
	defer gzWriter.Close()

	if _, err := io.Copy(gzWriter, input); err != nil {
		os.Remove(gzPath) // 压缩失败时删除部分文件
		return
	}

	// 压缩成功后删除原文件
	os.Remove(filePath)
}

// cleanOldFiles 清理旧文件
func (w *FileWriter) cleanOldFiles() {
	if w.config.MaxAge <= 0 && w.config.MaxBackups <= 0 {
		return
	}

	dir := filepath.Dir(w.config.FilePath)
	filename := filepath.Base(w.config.FilePath)
	ext := filepath.Ext(filename)
	name := strings.TrimSuffix(filename, ext)

	// 查找相关文件
	files, err := filepath.Glob(filepath.Join(dir, name+"_*"))
	if err != nil {
		return
	}

	var logFiles []fileInfo
	for _, file := range files {
		if stat, err := os.Stat(file); err == nil {
			logFiles = append(logFiles, fileInfo{
				path:    file,
				modTime: stat.ModTime(),
			})
		}
	}

	// 按修改时间排序
	sort.Slice(logFiles, func(i, j int) bool {
		return logFiles[i].modTime.After(logFiles[j].modTime)
	})

	// 按保留天数删除
	if w.config.MaxAge > 0 {
		cutoff := time.Now().AddDate(0, 0, -w.config.MaxAge)
		for _, file := range logFiles {
			if file.modTime.Before(cutoff) {
				os.Remove(file.path)
			}
		}
	}

	// 按备份数量删除
	if w.config.MaxBackups > 0 && len(logFiles) > w.config.MaxBackups {
		for _, file := range logFiles[w.config.MaxBackups:] {
			os.Remove(file.path)
		}
	}
}

// fileInfo 文件信息
type fileInfo struct {
	path    string
	modTime time.Time
}

// NetworkWriter 网络写入器
type NetworkWriter struct {
	config *OutputConfig
	conn   net.Conn
	mutex  sync.Mutex
}

// NewNetworkWriter 创建网络写入器
func NewNetworkWriter(config *OutputConfig) (*NetworkWriter, error) {
	writer := &NetworkWriter{
		config: config,
	}

	if err := writer.connect(); err != nil {
		return nil, err
	}

	return writer, nil
}

// Write 写入数据
func (w *NetworkWriter) Write(p []byte) (n int, err error) {
	w.mutex.Lock()
	defer w.mutex.Unlock()

	if w.conn == nil {
		if err := w.connect(); err != nil {
			return 0, err
		}
	}

	// 设置写入超时
	if w.config.Timeout > 0 {
		w.conn.SetWriteDeadline(time.Now().Add(w.config.Timeout))
	}

	n, err = w.conn.Write(p)
	if err != nil {
		// 连接断开，尝试重连
		w.conn.Close()
		w.conn = nil
		return n, err
	}

	return n, nil
}

// Close 关闭写入器
func (w *NetworkWriter) Close() error {
	w.mutex.Lock()
	defer w.mutex.Unlock()

	if w.conn != nil {
		err := w.conn.Close()
		w.conn = nil
		return err
	}
	return nil
}

// Sync 同步缓冲区
func (w *NetworkWriter) Sync() error {
	// 网络连接不需要同步
	return nil
}

// connect 建立连接
func (w *NetworkWriter) connect() error {
	conn, err := net.DialTimeout(w.config.Network, w.config.Address, w.config.Timeout)
	if err != nil {
		return fmt.Errorf("连接网络失败: %w", err)
	}

	w.conn = conn
	return nil
}

// BufferedWriter 缓冲写入器
type BufferedWriter struct {
	writer     Writer
	buffer     *bufio.Writer
	bufferSize int
	mutex      sync.Mutex
}

// NewBufferedWriter 创建缓冲写入器
func NewBufferedWriter(writer Writer, bufferSize int) *BufferedWriter {
	return &BufferedWriter{
		writer:     writer,
		buffer:     bufio.NewWriterSize(writer, bufferSize),
		bufferSize: bufferSize,
	}
}

// Write 写入数据
func (w *BufferedWriter) Write(p []byte) (n int, err error) {
	w.mutex.Lock()
	defer w.mutex.Unlock()

	return w.buffer.Write(p)
}

// Close 关闭写入器
func (w *BufferedWriter) Close() error {
	w.mutex.Lock()
	defer w.mutex.Unlock()

	w.buffer.Flush()
	return w.writer.Close()
}

// Sync 同步缓冲区
func (w *BufferedWriter) Sync() error {
	w.mutex.Lock()
	defer w.mutex.Unlock()

	if err := w.buffer.Flush(); err != nil {
		return err
	}
	return w.writer.Sync()
}

// MultiWriter 多重写入器
type MultiWriter struct {
	writers []Writer
}

// NewMultiWriter 创建多重写入器
func NewMultiWriter(writers ...Writer) *MultiWriter {
	return &MultiWriter{
		writers: writers,
	}
}

// Write 写入数据
func (w *MultiWriter) Write(p []byte) (n int, err error) {
	for _, writer := range w.writers {
		if _, err := writer.Write(p); err != nil {
			// 记录错误但继续写入其他输出
			continue
		}
	}
	return len(p), nil
}

// Close 关闭写入器
func (w *MultiWriter) Close() error {
	var lastErr error
	for _, writer := range w.writers {
		if err := writer.Close(); err != nil {
			lastErr = err
		}
	}
	return lastErr
}

// Sync 同步缓冲区
func (w *MultiWriter) Sync() error {
	var lastErr error
	for _, writer := range w.writers {
		if err := writer.Sync(); err != nil {
			lastErr = err
		}
	}
	return lastErr
}

// AddWriter 添加写入器
func (w *MultiWriter) AddWriter(writer Writer) {
	w.writers = append(w.writers, writer)
}

// RemoveWriter 移除写入器
func (w *MultiWriter) RemoveWriter(writer Writer) {
	for i, wr := range w.writers {
		if wr == writer {
			w.writers = append(w.writers[:i], w.writers[i+1:]...)
			break
		}
	}
}

// GetWriters 获取所有写入器
func (w *MultiWriter) GetWriters() []Writer {
	return w.writers
}

// AsyncWriter 异步写入器
type AsyncWriter struct {
	writer   Writer
	buffer   chan []byte
	done     chan struct{}
	wg       sync.WaitGroup
	maxSize  int
	dropMode bool // 是否丢弃模式
}

// NewAsyncWriter 创建异步写入器
func NewAsyncWriter(writer Writer, bufferSize int, dropMode bool) *AsyncWriter {
	aw := &AsyncWriter{
		writer:   writer,
		buffer:   make(chan []byte, bufferSize),
		done:     make(chan struct{}),
		maxSize:  bufferSize,
		dropMode: dropMode,
	}

	aw.wg.Add(1)
	go aw.writeLoop()

	return aw
}

// Write 写入数据
func (w *AsyncWriter) Write(p []byte) (n int, err error) {
	// 复制数据避免竞态条件
	data := make([]byte, len(p))
	copy(data, p)

	select {
	case w.buffer <- data:
		return len(p), nil
	default:
		if w.dropMode {
			// 丢弃模式：缓冲区满时直接丢弃
			return len(p), nil
		} else {
			// 阻塞模式：等待缓冲区有空间
			select {
			case w.buffer <- data:
				return len(p), nil
			case <-w.done:
				return 0, fmt.Errorf("异步写入器已关闭")
			}
		}
	}
}

// Close 关闭写入器
func (w *AsyncWriter) Close() error {
	close(w.done)
	w.wg.Wait()
	return w.writer.Close()
}

// Sync 同步缓冲区
func (w *AsyncWriter) Sync() error {
	// 等待缓冲区清空
	for len(w.buffer) > 0 {
		time.Sleep(10 * time.Millisecond)
	}
	return w.writer.Sync()
}

// writeLoop 写入循环
func (w *AsyncWriter) writeLoop() {
	defer w.wg.Done()

	for {
		select {
		case data := <-w.buffer:
			w.writer.Write(data)
		case <-w.done:
			// 处理剩余数据
			for len(w.buffer) > 0 {
				data := <-w.buffer
				w.writer.Write(data)
			}
			return
		}
	}
}

// GetBufferUsage 获取缓冲区使用率
func (w *AsyncWriter) GetBufferUsage() float64 {
	return float64(len(w.buffer)) / float64(w.maxSize)
}

// CreateWriter 根据配置创建写入器
func CreateWriter(config *OutputConfig) (Writer, error) {
	switch config.Type {
	case ConsoleTarget:
		return NewConsoleWriter(config.Writer), nil
	case FileTarget:
		return NewFileWriter(config)
	case NetworkTarget:
		return NewNetworkWriter(config)
	case CustomTarget:
		if config.CustomWriter == nil {
			return nil, fmt.Errorf("自定义写入器不能为空")
		}
		if writer, ok := config.CustomWriter.(Writer); ok {
			return writer, nil
		}
		// 包装为Writer接口
		return &writerWrapper{config.CustomWriter}, nil
	default:
		return nil, fmt.Errorf("不支持的输出类型: %d", config.Type)
	}
}

// writerWrapper io.Writer包装器
type writerWrapper struct {
	io.Writer
}

func (w *writerWrapper) Close() error {
	if closer, ok := w.Writer.(io.Closer); ok {
		return closer.Close()
	}
	return nil
}

func (w *writerWrapper) Sync() error {
	if syncer, ok := w.Writer.(interface{ Sync() error }); ok {
		return syncer.Sync()
	}
	return nil
}
